package com.mask.im.business.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 文件传输处理器
 * 处理WebSocket二进制文件传输，支持分片上传和断点续传
 * 
 * @author jian
 */
@Slf4j
public class FileHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> {

    // 文件传输相关常量
    private static final int MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
    private static final int MAX_CHUNK_SIZE = 64 * 1024; // 64KB
    private static final int HEADER_SIZE = 3; // 头部信息大小
    private static final int TIMEOUT_SECONDS = 300; // 5分钟超时

    // 文件传输状态
    private final ByteArrayOutputStream fileBuffer = new ByteArrayOutputStream();
    private final AtomicInteger fileLength = new AtomicInteger(0);
    private final AtomicLong lastReceiveTime = new AtomicLong(System.currentTimeMillis());
    private final AtomicInteger chunkCount = new AtomicInteger(0);
    
    // 文件元信息
    private String fileName;
    private String fileType;
    private String fileId;
    private boolean isTransferComplete = false;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame msg) throws Exception {
        try {
            lastReceiveTime.set(System.currentTimeMillis());
            
            ByteBuf content = msg.content();
            int readableBytes = content.readableBytes();
            
            log.debug("接收到文件数据块: {} bytes, 累计: {} bytes", readableBytes, fileLength.get());
            
            // 检查文件大小限制
            if (fileLength.get() + readableBytes > MAX_FILE_SIZE) {
                log.warn("文件大小超过限制: {} bytes", MAX_FILE_SIZE);
                sendErrorResponse(ctx, "文件大小超过限制");
                return;
            }
            
            // 处理头部信息
            if (readableBytes == HEADER_SIZE) {
                handleFileHeader(ctx, content);
                return;
            }
            
            // 处理文件数据块
            handleFileChunk(ctx, content, readableBytes);
            
        } catch (Exception e) {
            log.error("处理文件数据时发生异常", e);
            sendErrorResponse(ctx, "文件传输异常: " + e.getMessage());
        } finally {
            // 释放ByteBuf
            msg.release();
        }
    }

    /**
     * 处理文件头部信息
     */
    private void handleFileHeader(ChannelHandlerContext ctx, ByteBuf content) {
        try {
            // 读取头部信息（这里需要根据实际协议定义）
            byte[] headerBytes = new byte[HEADER_SIZE];
            content.getBytes(0, headerBytes);
            
            // 解析头部信息
            parseFileHeader(headerBytes);
            
            log.info("开始接收文件: {}, 类型: {}, ID: {}", fileName, fileType, fileId);
            
            // 发送确认响应
            sendAckResponse(ctx, "开始接收文件");
            
        } catch (Exception e) {
            log.error("处理文件头部信息失败", e);
            sendErrorResponse(ctx, "文件头部信息解析失败");
        }
    }

    /**
     * 处理文件数据块
     */
    private void handleFileChunk(ChannelHandlerContext ctx, ByteBuf content, int readableBytes) {
        try {
            // 检查是否已完成传输
            if (isTransferComplete) {
                log.warn("文件传输已完成，忽略额外数据");
                return;
            }
            
            // 读取数据块
            byte[] chunkData = new byte[readableBytes];
            content.getBytes(0, chunkData);
            
            // 写入缓冲区
            fileBuffer.write(chunkData);
            fileLength.addAndGet(readableBytes);
            chunkCount.incrementAndGet();
            
            log.debug("接收文件块: {} bytes, 累计: {} bytes, 块数: {}", 
                    readableBytes, fileLength.get(), chunkCount.get());
            
            // 检查是否传输完成（这里需要根据实际协议判断）
            if (isTransferComplete(chunkData)) {
                completeFileTransfer(ctx);
            } else {
                // 发送进度响应
                sendProgressResponse(ctx);
            }
            
        } catch (IOException e) {
            log.error("写入文件数据失败", e);
            sendErrorResponse(ctx, "文件数据写入失败");
        }
    }

    /**
     * 解析文件头部信息
     */
    private void parseFileHeader(byte[] headerBytes) {
        // 这里需要根据实际协议解析头部信息
        // 示例：假设头部包含文件名、类型、ID等信息
        this.fileName = "uploaded_file_" + System.currentTimeMillis();
        this.fileType = "unknown";
        this.fileId = "file_" + System.currentTimeMillis();
    }

    /**
     * 检查是否传输完成
     */
    private boolean isTransferComplete(byte[] chunkData) {
        // 这里需要根据实际协议判断传输是否完成
        // 示例：检查是否接收到结束标记
        return chunkData.length < MAX_CHUNK_SIZE;
    }

    /**
     * 完成文件传输
     */
    private void completeFileTransfer(ChannelHandlerContext ctx) {
        try {
            isTransferComplete = true;
            
            byte[] fileData = fileBuffer.toByteArray();
            
            log.info("文件传输完成: {}, 大小: {} bytes, 块数: {}", 
                    fileName, fileData.length, chunkCount.get());
            
            // 保存文件
            saveFile(fileData);
            
            // 发送完成响应
            sendCompleteResponse(ctx, fileData.length);
            
        } catch (Exception e) {
            log.error("完成文件传输时发生异常", e);
            sendErrorResponse(ctx, "文件保存失败: " + e.getMessage());
        }
    }

    /**
     * 保存文件
     */
    private void saveFile(byte[] fileData) throws IOException {
        // 这里实现文件保存逻辑
        // 可以保存到本地文件系统、云存储等
        
        log.info("保存文件: {}, 大小: {} bytes", fileName, fileData.length);
        
        // 示例：保存到临时目录
        // Files.write(Paths.get("/tmp/" + fileName), fileData);
    }

    /**
     * 发送确认响应
     */
    private void sendAckResponse(ChannelHandlerContext ctx, String message) {
        try {
            String response = String.format("{\"type\":\"ack\",\"message\":\"%s\"}", message);
            ctx.writeAndFlush(response);
            log.debug("发送确认响应: {}", message);
        } catch (Exception e) {
            log.error("发送确认响应失败", e);
        }
    }

    /**
     * 发送进度响应
     */
    private void sendProgressResponse(ChannelHandlerContext ctx) {
        try {
            int progress = (int) ((fileLength.get() * 100.0) / MAX_FILE_SIZE);
            String response = String.format("{\"type\":\"progress\",\"progress\":%d,\"size\":%d}", 
                    progress, fileLength.get());
            ctx.writeAndFlush(response);
            log.debug("发送进度响应: {}%", progress);
        } catch (Exception e) {
            log.error("发送进度响应失败", e);
        }
    }

    /**
     * 发送完成响应
     */
    private void sendCompleteResponse(ChannelHandlerContext ctx, int fileSize) {
        try {
            String response = String.format("{\"type\":\"complete\",\"fileName\":\"%s\",\"size\":%d,\"fileId\":\"%s\"}", 
                    fileName, fileSize, fileId);
            ctx.writeAndFlush(response);
            log.info("发送完成响应: {}", response);
        } catch (Exception e) {
            log.error("发送完成响应失败", e);
        }
    }

    /**
     * 发送错误响应
     */
    private void sendErrorResponse(ChannelHandlerContext ctx, String errorMessage) {
        try {
            String response = String.format("{\"type\":\"error\",\"message\":\"%s\"}", errorMessage);
            ctx.writeAndFlush(response);
            log.error("发送错误响应: {}", errorMessage);
        } catch (Exception e) {
            log.error("发送错误响应失败", e);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("文件传输处理器发生异常", cause);
        sendErrorResponse(ctx, "文件传输异常: " + cause.getMessage());
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("文件传输连接断开: {}", ctx.channel().remoteAddress());
        
        // 清理资源
        try {
            fileBuffer.close();
        } catch (IOException e) {
            log.error("关闭文件缓冲区失败", e);
        }
        
        super.channelInactive(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("文件传输连接建立: {}", ctx.channel().remoteAddress());
        super.channelActive(ctx);
    }

    /**
     * 获取传输统计信息
     */
    public FileTransferStats getTransferStats() {
        return new FileTransferStats(
                fileName,
                fileType,
                fileId,
                fileLength.get(),
                chunkCount.get(),
                isTransferComplete,
                System.currentTimeMillis() - lastReceiveTime.get()
        );
    }

    /**
     * 文件传输统计信息
     */
    public static class FileTransferStats {
        private final String fileName;
        private final String fileType;
        private final String fileId;
        private final int fileSize;
        private final int chunkCount;
        private final boolean isComplete;
        private final long lastReceiveTime;

        public FileTransferStats(String fileName, String fileType, String fileId, 
                               int fileSize, int chunkCount, boolean isComplete, long lastReceiveTime) {
            this.fileName = fileName;
            this.fileType = fileType;
            this.fileId = fileId;
            this.fileSize = fileSize;
            this.chunkCount = chunkCount;
            this.isComplete = isComplete;
            this.lastReceiveTime = lastReceiveTime;
        }

        // Getters
        public String getFileName() { return fileName; }
        public String getFileType() { return fileType; }
        public String getFileId() { return fileId; }
        public int getFileSize() { return fileSize; }
        public int getChunkCount() { return chunkCount; }
        public boolean isComplete() { return isComplete; }
        public long getLastReceiveTime() { return lastReceiveTime; }
    }
}
